from flask import Flask, request, jsonify, send_file, Response
from word import GetWord
import os
import json
from werkzeug.utils import secure_filename as sf
from excel_processor import ExcelProcessor
import tempfile
from deepseek_api import DeepseekAPI
import importlib
import time

# 检查OpenAI库版本
try:
    openai_version = importlib.import_module("openai").__version__
    print(f"当前使用的OpenAI库版本: {openai_version}")
except ImportError:
    print("警告: 未能检测到OpenAI库版本")
    openai_version = "未知"

# 加载环境变量
try:
    from dotenv import load_dotenv
    load_dotenv()
    print(f"环境变量加载成功，DEEPSEEK_API_KEY: {'已设置' if os.getenv('DEEPSEEK_API_KEY') else '未设置'}")
except ImportError:
    print("警告: python-dotenv未安装，无法从.env文件加载环境变量")

# 尝试导入loguru，如果失败则使用标准logging
try:
    from loguru import logger
    import sys
    import datetime
    
    # 配置loguru日志
    log_path = os.path.join(os.path.dirname(__file__), "log")
    # 确保日志目录存在
    try:
        if not os.path.exists(log_path):
            os.makedirs(log_path)
            
        # 配置日志格式和存储
        logger.remove()  # 移除默认处理器
        # 添加标准输出处理器
        logger.add(sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}")
        # 添加文件处理器，按日期归档
        logger.add(
            os.path.join(log_path, "{time:YYYY-MM-DD}.log"),
            rotation="00:00",  # 每天零点创建新的日志文件
            encoding="utf-8",
            format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}",
            retention="30 days",  # 保留30天的日志
            catch=True  # 捕获异常，防止日志错误导致应用崩溃
        )
        
        use_loguru = True
    except Exception as e:
        print(f"警告: 配置日志时出错: {str(e)}，将使用标准输出")
        use_loguru = False
        
except ImportError:
    import logging
    
    # 使用标准logging模块
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s | %(levelname)-8s | %(name)s:%(funcName)s:%(lineno)d - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    logger = logging.getLogger(__name__)
    use_loguru = False
    print("警告: loguru库未安装，使用标准logging模块")

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 限制文件大小为16MB

# 确保上传目录存在
if not os.path.exists(app.config['UPLOAD_FOLDER']):
    os.makedirs(app.config['UPLOAD_FOLDER'])

# 安全的日志函数，防止日志错误导致应用崩溃
def safe_log(level, message):
    try:
        if level == 'info':
            logger.info(message)
        elif level == 'error':
            logger.error(message)
        elif level == 'debug':
            logger.debug(message)
        elif level == 'warning':
            logger.warning(message)
        elif level == 'exception':
            logger.exception(message)
    except Exception as e:
        print(f"日志记录失败: {str(e)}, 原始消息: {message}")

# 添加请求日志中间件
@app.before_request
def before_request():
    try:
        safe_log('info', f"Request: {request.method} {request.path} {dict(request.args)}")
    except Exception:
        pass

@app.after_request
def after_request(response):
    try:
        safe_log('info', f"Response: {response.status}")
    except Exception:
        pass
    return response

@app.route('/')
def index():
    return app.send_static_file('index.html')

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        safe_log('error', "没有文件上传")
        return jsonify({'error': '没有文件上传'}), 400
    
    file = request.files['file']
    if file.filename == '':
        safe_log('error', "没有选择文件")
        return jsonify({'error': '没有选择文件'}), 400
    
    filename = sf(file.filename)
    filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    file.save(filepath)
    safe_log('info', f"上传文件已保存: {filename}")

    try:
        # 判断文件类型
        if file.filename.endswith('.docx'):
            safe_log('info', f"开始处理Word文档: {filename}")
            word_converter = GetWord()
            document = word_converter.get_document("", filepath)
            content = json.loads(document.page_content)
            
            # 删除临时文件
            os.remove(filepath)
            safe_log('info', f"Word文档处理完成，临时文件已删除")
            
            return jsonify({
                'success': True,
                'content': content
            })
        elif file.filename.endswith('.xlsx'):
            # 这里仅保存文件，不进行处理
            safe_log('info', f"Excel文件已上传: {filename}")
            return jsonify({
                'success': True,
                'message': '已上传Excel文件',
                'filename': filename
            })
        else:
            os.remove(filepath)  # 删除不支持的文件
            return jsonify({'error': '不支持的文件类型，仅支持.docx和.xlsx文件'}), 400
    except Exception as e:
        # 确保清理临时文件
        if os.path.exists(filepath):
            os.remove(filepath)
        safe_log('exception', f"处理上传文件异常: {str(e)}")
        return jsonify({'error': str(e)}), 500

@app.route('/process-excel', methods=['POST'])
def process_excel():
    """处理已上传的Excel文件，生成prompt"""
    data = request.get_json()
    if not data or 'filename' not in data:
        safe_log('error', "请求缺少Excel文件名")
        return jsonify({'error': '请提供Excel文件名'}), 400
    
    filename = data['filename']
    filepath = os.path.join(app.config['UPLOAD_FOLDER'], sf(filename))
    safe_log('info', f"处理Excel文件: {filename}")
    
    if not os.path.exists(filepath):
        safe_log('error', f"文件不存在: {filepath}")
        return jsonify({'error': '文件不存在，请重新上传'}), 404
    
    try:
        processor = ExcelProcessor()
        safe_log('info', f"开始处理Excel文件: {filename}")
        result = processor.process_excel(filepath)
        
        if not result['success']:
            safe_log('error', f"Excel处理失败: {result['message']}")
            return jsonify({'error': result['message']}), 400
            
        # 返回临时文件路径，用于下载
        safe_log('info', f"Excel处理成功: {result['message']}, 文件路径: {result['file_path']}")
        return jsonify({
            'success': True,
            'message': result['message'],
            'download_path': f"/download-excel/{os.path.basename(result['file_path'])}"
        })
    except Exception as e:
        safe_log('exception', f"处理Excel异常: {str(e)}")
        return jsonify({'error': f'处理Excel失败: {str(e)}'}), 500

@app.route('/download-excel/<filename>', methods=['GET'])
def download_excel(filename):
    """下载生成的Excel文件"""
    # 在临时目录中查找文件
    temp_dir = tempfile.gettempdir()
    filepath = None
    safe_log('info', f"请求下载Excel文件: {filename}")
    
    # 搜索临时目录中的文件
    for root, dirs, files in os.walk(temp_dir):
        if filename in files:
            filepath = os.path.join(root, filename)
            break
    
    if not filepath or not os.path.exists(filepath):
        safe_log('error', f"下载的文件不存在: {filename}")
        return jsonify({'error': '文件不存在或已过期'}), 404
        
    try:
        safe_log('info', f"文件已找到，准备下载: {filepath}")
        return send_file(filepath, as_attachment=True, 
                          download_name=filename)
    except Exception as e:
        safe_log('exception', f"下载文件异常: {str(e)}")
        return jsonify({'error': f'下载文件失败: {str(e)}'}), 500

@app.route('/api/chat-stream', methods=['POST'])
def chat_stream():
    """处理流式聊天请求"""
    try:
        data = request.json
        if not data:
            safe_log('error', "聊天请求参数无效")
            return jsonify({'error': '请求参数无效'}), 400
            
        messages = data.get('messages', [])
        max_tokens = data.get('max_tokens', 2048)
        safe_log('info', f"接收到聊天请求: 消息数量={len(messages)}, 最大令牌数={max_tokens}")
        
        if not messages or not isinstance(messages, list) or len(messages) == 0:
            safe_log('error', "聊天消息格式不正确")
            return jsonify({'error': '消息格式不正确'}), 400
        
        # 创建DeepSeek API客户端
        api = DeepseekAPI()
        safe_log('info', "开始流式聊天请求处理")
        
        def generate():
            # 获取流式响应
            try:
                stream_response = api.chat_completion(messages, max_tokens=max_tokens, stream=True)
                safe_log('debug', "获取流式响应成功，开始处理")
                
                # 处理每个响应块
                for chunk in stream_response:
                    if hasattr(chunk.choices[0].delta, 'reasoning_content') and chunk.choices[0].delta.reasoning_content:
                        # 输出思维链内容
                        yield chunk.choices[0].delta.reasoning_content
                    elif hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
                        # 输出最终回答内容
                        yield chunk.choices[0].delta.content
                
                safe_log('info', "流式聊天响应处理完成")
            except Exception as e:
                safe_log('exception', f"流式响应处理异常: {str(e)}")
                yield f"处理出错: {str(e)}"
        
        # 返回流式响应
        return Response(generate(), mimetype='text/plain')
    except Exception as e:
        safe_log('exception', f"处理聊天请求异常: {str(e)}")
        return jsonify({'error': f'处理聊天请求失败: {str(e)}'}), 500

@app.route('/review-document', methods=['POST'])
def review_document():
    """文档审核功能，使用DeepSeek R1模型"""
    try:
        if 'wordFile' not in request.files or 'excelFile' not in request.files:
            safe_log('error', "文档审核请求缺少必要的文件")
            return jsonify({'error': '缺少必要的文件'}), 400
            
        word_file = request.files['wordFile']
        excel_file = request.files['excelFile']
        model_type = request.form.get('modelType', 'deepseek')
        safe_log('info', f"接收到文档审核请求: Word文件={word_file.filename}, Excel文件={excel_file.filename}, 模型类型={model_type}")
        
        # 保存上传的文件
        word_filename = sf(word_file.filename)
        excel_filename = sf(excel_file.filename)
        
        word_filepath = os.path.join(app.config['UPLOAD_FOLDER'], word_filename)
        excel_filepath = os.path.join(app.config['UPLOAD_FOLDER'], excel_filename)
        
        word_file.save(word_filepath)
        excel_file.save(excel_filepath)
        safe_log('info', f"审核文件已保存: Word={word_filepath}, Excel={excel_filepath}")
        
        # 解析Word文档内容
        word_converter = GetWord()
        document = word_converter.get_document("", word_filepath)
        word_content = json.loads(document.page_content)
        
        # 处理Excel文件
        try:
            import pandas as pd
            df = pd.read_excel(excel_filepath)
            
            # 确保结果和thinking列存在
            if 'result' not in df.columns:
                df['result'] = ''
            if 'thinking' not in df.columns:
                df['thinking'] = ''
                
            # 创建DeepSeek API客户端
            api = DeepseekAPI()
            
            # 处理每一行
            for index, row in df.iterrows():
                # 构建提示词(从excel的prompt列获取)
                prompt = row.get('prompt', '')
                if not prompt:
                    continue
                    
                # 替换提示词中的占位符
                for key in word_content:
                    placeholder = f"{{{{document.{key}}}}}"
                    if placeholder in prompt:
                        prompt = prompt.replace(placeholder, word_content[key])
                
                # 构建消息
                messages = [{"role": "user", "content": prompt}]
                
                # 调用API
                response = api.chat_completion(messages)
                
                # 提取结果
                thinking = response.choices[0].message.reasoning_content
                result = response.choices[0].message.content
                
                # 更新Excel
                df.at[index, 'thinking'] = thinking
                df.at[index, 'result'] = result
            
            # 保存结果到临时文件
            import tempfile
            output_file = tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx')
            df.to_excel(output_file.name, index=False)
            
            # 清理原始上传文件
            os.remove(word_filepath)
            os.remove(excel_filepath)
            
            safe_log('info', f"文档审核完成，结果已保存到: {output_file.name}")
            return jsonify({
                'success': True,
                'message': '文档审核完成',
                'download_path': f"/download-excel/{os.path.basename(output_file.name)}"
            })
                
        except Exception as e:
            safe_log('exception', f"处理Excel异常: {str(e)}")
            return jsonify({'error': f'处理Excel失败: {str(e)}'}), 500
        
    except Exception as e:
        safe_log('exception', f"审核文档异常: {str(e)}")
        return jsonify({'error': f'审核文档失败: {str(e)}'}), 500

@app.route('/api/review', methods=['POST'])
def api_review():
    try:
        # 获取请求参数
        data = request.json
        
        if not data:
            return jsonify({
                "error": "请求参数为空",
                "result": "无效的请求",
                "thinking": "请求数据为空"
            }), 400
        
        if 'content' not in data:
            return jsonify({
                "error": "请求缺少content字段",
                "result": "无效的请求",
                "thinking": "缺少必要参数"
            }), 400
        
        # 初始化DeepSeek API
        api = DeepseekAPI()
        
        # 调用文档审核方法
        logger.info(f"开始文档审核，内容长度: {len(data['content'])} 字符")
        
        review_result = api.review_document(
            content=data['content'],
            prompt_template=data.get('prompt_template')
        )
        
        logger.info("文档审核完成")
        
        return jsonify(review_result)
    
    except Exception as e:
        logger.error(f"文档审核失败: {str(e)}")
        return jsonify({
            "error": f"文档审核失败: {str(e)}",
            "result": f"处理请求时发生错误: {str(e)}",
            "thinking": "服务器内部错误"
        }), 500

@app.route('/api/chat', methods=['POST'])
def api_chat():
    try:
        # 获取请求参数
        data = request.json
        
        if not data:
            return jsonify({
                "error": "请求参数为空",
                "content": "无效的请求"
            }), 400
        
        if 'messages' not in data:
            return jsonify({
                "error": "请求缺少messages字段",
                "content": "无效的请求"
            }), 400
        
        # 初始化DeepSeek API
        api = DeepseekAPI()
        
        # 调用聊天方法
        logger.info(f"开始聊天请求，模型: {data.get('model', 'deepseek-chat')}")
        
        stream = data.get('stream', False)
        
        if stream:
            # 流式输出处理
            def generate():
                try:
                    response_stream = api.chat_completion(
                        messages=data['messages'],
                        model=data.get('model', 'deepseek-chat'),
                        max_tokens=data.get('max_tokens', 2048),
                        stream=True
                    )
                    
                    for chunk in response_stream:
                        yield f"data: {json.dumps(chunk)}\n\n"
                    
                    yield "data: [DONE]\n\n"
                except Exception as e:
                    logger.error(f"流式输出发生错误: {str(e)}")
                    yield f"data: {json.dumps({'error': str(e)})}\n\n"
                    yield "data: [DONE]\n\n"
            
            logger.info("返回流式响应")
            return Response(generate(), mimetype='text/event-stream')
        else:
            # 非流式输出
            response = api.chat_completion(
                messages=data['messages'],
                model=data.get('model', 'deepseek-chat'),
                max_tokens=data.get('max_tokens', 2048)
            )
            
            if hasattr(response, 'choices') and len(response.choices) > 0:
                result = {
                    'content': response.choices[0].message.content,
                    'reasoning_content': getattr(response.choices[0].message, 'reasoning_content', None)
                }
            else:
                result = {'error': '无法获取响应结果'}
            
            logger.info("聊天请求完成")
            return jsonify(result)
    
    except Exception as e:
        logger.error(f"聊天请求失败: {str(e)}")
        return jsonify({
            "error": f"聊天请求失败: {str(e)}",
            "content": f"处理请求时发生错误: {str(e)}"
        }), 500

@app.route('/api/status', methods=['GET'])
def api_status():
    try:
        # 检查API密钥是否配置
        api_key_status = "已配置" if os.getenv('DEEPSEEK_API_KEY') else "未配置"
        
        return jsonify({
            "status": "正常",
            "api_key": api_key_status,
            "openai_version": openai_version,
            "timestamp": time.time()
        })
    
    except Exception as e:
        logger.error(f"状态检查失败: {str(e)}")
        return jsonify({
            "status": "异常",
            "error": str(e),
            "openai_version": openai_version
        }), 500

if __name__ == '__main__':
    try:
        safe_log('info', "===== API服务启动 =====")
        safe_log('info', f"日志保存路径: {log_path if 'log_path' in locals() else '使用标准输出'}")
        safe_log('info', "服务将同时监听IPv4和IPv6接口")
        
        # 尝试监听IPv4
        try:
            import socket
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.bind(('0.0.0.0', 5000))
            sock.close()
            safe_log('info', "IPv4接口（0.0.0.0:5000）可用")
        except Exception as e:
            safe_log('warning', f"测试IPv4接口时出错: {str(e)}")
        
        # 启动Flask应用
        # 强制使用IPv4
        app.run(debug=True, port=5000, host='0.0.0.0', threaded=True)
    except Exception as e:
        print(f"服务启动异常: {str(e)}")
        if use_loguru:
            logger.exception("服务启动异常")
        sys.exit(1)
